"""
字符串 生成器
"""

import random
import time
from typing import Union

from utils.mock_utils import DATETIME


class StringGenerator:
    """
    生成器（非 Python 生成器）

    生成的字符中，移除下列元素（仅为避免混淆）：
        - 数字：0、1
        - 字母：i、o
    """

    number: str = "23456789"
    symbol: str = "~!@#$%^*()_+-="
    letter: str = "ABCDEFGHGKMNPQRSTUVWXYZ"  # noqa

    @classmethod
    def generate_code(
        cls,
        length: int,
        letter_l: bool = False,
        letter_u: bool = False,
        integer: bool = False,
        symbol: bool = False,
        mixed: bool = True,
    ) -> str:
        """
        生成指定长度的随机码

        >>> StringGenerator.generate_code(
        ...     length=10,
        ...     letter_l=True,
        ... )
        "skvmbythpz"

        >>> StringGenerator.generate_code(
        ...     length=10,
        ...     letter_u=True,
        ... )
        "KLAYZHGBQT"

        >>> StringGenerator.generate_code(
        ...     length=10,
        ...     integer=True,
        ... )
        "2564836795"

        >>> StringGenerator.generate_code(
        ...     length=10,
        ...    symbol=True,
        ... )
        "~@#%*)_+-="

        >>> StringGenerator.generate_code(
        ...     length=10,
        ...     mixed=True,
        ... )
        "j@dDa56v#K"

        :param length:      长度
        :param letter_l:    是否纯字母（小写）
        :param letter_u:    是否纯字母（大写）
        :param integer:     是否纯数字
        :param symbol:      是否纯符号
        :param mixed:       是否使用混合
        :return:            code 字符串
        :raise ValueError1: length 必须大于0
        :raise ValueError2: letter_l、letter_u、integer、symbol、mixed 必须有一个为 True
        """

        if not length > 0:
            raise ValueError(f"length 必须大于0，当前为: {length}")

        if not any((letter_l, letter_u, integer, symbol, mixed)):
            raise ValueError("必须有一个为 True")

        if sum((letter_l, letter_u, integer, symbol, mixed)) > 1:
            raise ValueError("只能选择一种")

        base_str: str = ""

        if letter_l:
            base_str = cls.letter.lower()

        elif letter_u:
            base_str = cls.letter.upper()

        elif integer:
            base_str = cls.number

        elif symbol:
            base_str = cls.symbol

        elif mixed:
            base_str = cls.letter.lower() + cls.letter.upper() + cls.number + cls.symbol

        return "".join(
            base_str[random.randint(0, len(base_str) - 1)]
            for _ in range(length)
        )

    @classmethod
    def generate_captcha(
        cls,
        length: int,
        is_string: bool = False,
    ) -> Union[int, str]:
        """
        生成指定长度的数字验证码

        >>> StringGenerator.generate_captcha(length=6)
        248659

        >>> StringGenerator.generate_captcha(
        ...     length=6,
        ...     is_string=True,
        ... )
        "248659"

        :param length:      长度
        :param is_string:   是否为字符串
        :return:            字符串/数字
        :raise ValueError:  length 必须大于0
        """

        if not length > 0:
            raise ValueError(f"length 必须大于0，当前为: {length}")

        base_str: str = cls.number
        random_str: Union[int, str] = "".join(
            base_str[random.randint(0, len(base_str) - 1)]
            for _ in range(length)
        )

        if not is_string:
            random_str = int(random_str)

        return random_str

    @classmethod
    def generate_unique_code(cls, prefix: str = "") -> str:
        """
        生成唯一的 code（可反向解出code的生成时间）  15位

        >>> StringGenerator.generate_unique_code()
        "210922289818674"

        >>> StringGenerator.generate_unique_code(prefix="CATEGORY")
        "CATEGORY_210922289818674"

        :param prefix:  code 前缀
        :return:        code
        """

        now: str = str(DATETIME().now())
        time_part_1: str = now[2:4] + now[5:7] + now[8:10]  # ->                    年份后2位 + 月 + 日
        time_part_2: str = str(time.time())[4:10] + str(time.time())[11:14]  # ->   时间戳4-9位 + 时间戳11-13位
        time_part: str = time_part_1 + time_part_2
        time.sleep(0.01)  # ->                                                      避免并发时产生同样的数据

        return "_".join((prefix, time_part))  # ->                                  prefix + _ + 210922 + 289818 + 674

    @classmethod
    def generate_random_str(cls, random_length: int = 16) -> str:
        """
        生成一个指定长度的随机字符串

        >>> StringGenerator.generate_random_str()
        "f52At8V2z8hes24E"

        >>> StringGenerator.generate_random_str(random_length=10)
        "59G2aT4LbR"

        :param random_length:   指定长度
        :return:                随机字符串
        :raise ValueError:      random_length 必须大于 0
        """

        if not random_length > 0:
            raise ValueError(f"random_length 必须大于0，当前为: {random_length}")

        base_str: str = "".join((cls.letter, cls.letter.lower(), cls.number))

        return "".join(
            base_str[random.randint(0, len(base_str) - 1)]
            for _ in range(random_length)
        )
